#pragma once
#include <iostream>
#include <unordered_map>
#include "Connection.hpp"
#include "Epoller.hpp"

class Reactor
{
    const static int gnum = 64;

public:
    Reactor()
        : _isrunning(false) {}

    void AddConnetion(int fd, uint32_t events, func_t recver, func_t sender, func_t excepter)
    {
        // 构建connection
        Connection *conn = new Connection(fd);
        conn->Setevents(events);
        conn->Register(recver, sender, excepter);
        conn->SetSelf(this);

        // epoll添加对事件的关心
        _epoller.AddEvent(fd, events);

        _connections.insert({fd, conn});
    }

    void LoopOnce(int timeout)
    {
        int n = _epoller.Wait(_revs, gnum, timeout);
        for (int i = 0; i < n; i++)
        {
            int sockfd = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;
            if (revents & EPOLLHUP)
                revents |= EPOLLIN | EPOLLOUT;
            if (revents & EPOLLERR)
                revents |= EPOLLIN | EPOLLOUT;
            if (revents & EPOLLIN)
            {
                if (ConnectionIsExists(sockfd) && _connections[sockfd]->_recver != nullptr)
                    _connections[sockfd]->_recver(_connections[sockfd]);
            }
            if (revents & EPOLLOUT)
            {
                if (ConnectionIsExists(sockfd) && _connections[sockfd]->_sender != nullptr)
                    _connections[sockfd]->_sender(_connections[sockfd]);
            }
        }
    }

    void Dispatcher()
    {
        _isrunning = true;
        int timeout = 3000;
        while (_isrunning)
        {
            LoopOnce(timeout);
            Debug();
        }
        _isrunning = false;
    }

    void EnableReadWrite(int sockfd, bool readable, bool writeable)
    {
        uint32_t events = (readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET;
        if (ConnectionIsExists(sockfd))
        {
            // 1. 修改connection关心的事件
            _connections[sockfd]->Setevents(events);
            // 2.写入内核
            _epoller.ModEvent(sockfd, events);
        }
        Debug();
    }
    void RemoveConnetion(int sockfd)
    {
        if (ConnectionIsExists(sockfd))
        {
            // 1. 取消epoll关心
            _epoller.DelEvent(sockfd);
            // 2. 关闭sockfd
            _connections[sockfd]->Close();
            // 3.释放connection
            delete _connections[sockfd];
            _connections.erase(sockfd);
        }
    }

    bool ConnectionIsExists(int sockfd)
    {
        auto iter = _connections.find(sockfd);
        return iter != _connections.end();
    }

    void Debug()
    {
        std::cout << "----------------------------------" << std::endl;
        for (auto &connection : _connections)
        {
            std::cout << "fd: " << connection.second->Sockfd() << ", ";
            uint32_t events = connection.second->Events();
            if ((events & EPOLLIN) && (events & EPOLLET))
                std::cout << "EPOLLIN | EPOLLET, ";
            if ((events & EPOLLOUT) && (events & EPOLLET))
                std::cout << "EPOLLOUT | EPOLLET";
            std::cout << std::endl;
        }
        std::cout << "----------------------------------" << std::endl;
    }

    ~Reactor() {}

private:
    std::unordered_map<int, Connection *> _connections;
    struct epoll_event _revs[gnum];
    Epoller _epoller;
    bool _isrunning;
};